flutter - 动画实现
前言
动画是客户端开发中非常重要的一个方面,良好的动画设计能带给用户非常好的交互体。flutter 提供了一个非常灵活的动画框架,可以非常轻松地实现各种动效。这篇文章就将带你深入了解。
从 AnimationController.forward 方法开始
AnimationController.forward 是最常用的启动动画的方法,该方法调用后 AnimationController.value 值会在持续时间内持续变化,我们可以从这个方法开始分析整个 flutter 的动画实现原理
AnimationController.forward
1 | TickerFuture forward({ double from }) { |
确定了动画的方向,以及可能的动画起始值,返回值是一个 TickerFuture 类型的异步任务
AnimationController._animateToInternal
1 | TickerFuture _animateToInternal(double target, { Duration duration, Curve curve: Curves.linear }) { |
会根据目标值 target 和起始值 _value 计算整个动画的持续时间。先通过 stop 方法暂停可以存在的动画。如果计算出的持续时间为 0,意味着不需要进行动画,回调一些必要的 Listener 后结束,否则就开始启动动画,调用 _startSimulation(new _InterpolationSimulation(_value, target, simulationDuration, curve)) 方法。
AnimationController._startSimulation
1 | TickerFuture _startSimulation(Simulation simulation) { |
Simulation 是用来模拟在一维空间中一个物体受力改变的情况,通过 x 函数可以获取给定时间物体的位置,dx 函数可以获取给定时间物体的速度,isDone 函数获取给定时间是否完成。通过自定义各种各样的 simulation 可以模拟出真实场景下的动画效果。接下去我们可以看到动画运行的关键 _ticker.start()
AnimationController 的构造函数中 TickerProvider 是一个必要的参数,通过 TickerProvider.createTicker(TickerCallback onTick) 方法可以生成 _ticker(Ticker) 对象,那么这个 _ticker 到底是用来干嘛的
Ticker 是每一帧用来调用动画回调的,它由 SchedulerBinding 驱动,什么意思呢,我们可以从 start 方法深入了解
Ticker.start
1 | TickerFuture start() { |
回调添加在 scheduleTick 方法进行,随后记录了起始时间
Ticker.scheduleTick
1 | void scheduleTick({ bool rescheduling: false }) { |
这时 Ticker 会向 SchedulerBinding 通过 scheduleFrameCallback 注册帧回调,回调方法为 _tick,记录当前帧的回调主键 _animationId,可用于取消动画时注销回调
在 ScheduleBinding 初始化的工作中,ui.window.onBeginFrame = _handleBeginFrame,这里将从 flutter 引擎传来的每一帧开时回调传递给 _handleBeginFrame 方法,在该方法中会回调注册过的动画回调
1 | try { |
这里会遍历 callbacks,排除掉已经移除的回调方法,依次触发回调方法,回到 Ticker._tick
Tick._tick
1 | void _tick(Duration timeStamp) { |
这里就会回调 AnimationController._tick,但是这里传递的 time 就是已经减去起始值的持续时间了,最后还会根据是否需要注册下一帧的回调
AnimationController._tick
1 | void _tick(Duration elapsed) { |
根据 elapsed 和 _simulation 计算当前的 value 值,当判断动画结束时就通过 stop 方法调用 ticker.stop 结束回调,具体操作也就是根据 _animationId 去移除回调方法,然后结束代表动画任务的 TickerFuture,重置参数,unscheduleTick
对于其他的方法操作 [reverse]、[animateTo]、[animateWith]、[fling] 和 [repeat], 都是类似的原理,可能具体实施有些区别或者 Simulation 不同而已